﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.DirectoryServices;
using System.Text;

//////////////////////////////////////////////////////////////////////////
//LdapAuthentication.cs                                                 //
//Last Edited: 21 Mar 2012                                              //
//                                                                      //
//This class contains all the code for authenticating users against     //
//  the Active Directory (AD) server using the lightweight directory    //
//  access protocol (LDAP).                                             //
//Using code modified from a Microsoft tutorial:                        //
//http://msdn.microsoft.com/en-us/library/ff649227.aspx                 //
//////////////////////////////////////////////////////////////////////////
public class LdapAuthentication
{
    //////////////////////
    //Instance Variables//
    //////////////////////
    private String _path; //The path to the Active Directory server
    private String _filterAttribute; //Properties for LDAP queries
    public class AuthenticationException : Exception //Exception for when error occurs during authentication
    {
        public AuthenticationException() : base() { }
        public AuthenticationException(string message) : base(message) { }
        public AuthenticationException(string message, System.Exception inner) : base(message, inner) { }
    };

    ////////////////
    //Constructors//
    ////////////////

    /// <summary>
    /// LdapAuthentication()
    /// Constructor
    /// 
    /// Construct an object to authenticate users against the AD server
    ///     at the path specified by the parameter.
    /// </summary>
    /// <param name="path">String path - the path to the AD server</param>
	public LdapAuthentication(String path)
    {
        //Set instance variables
        _path = path;
    } //end LdapAuthenticaion()

    ////////////////////
    //Public Functions//
    ////////////////////

    /// <summary>
    /// IsAuthenticated()
    /// 
    /// Determines if a user with the given name and password
    /// can be authenticated against the AD server.
    /// </summary>
    /// <param name="domain">String domain - the domain the user belongs to</param>
    /// <param name="domain">String username - the user's login name</param>
    /// <param name="domain">String pwd - the user's password</param>
    /// <returns>True if user login is valid, false otherwise</returns>
    public bool IsAuthenticated(String domain, String username, String pwd)
    {
        //Create a directory entry to be used in a query
        //Note: prefixing an @ before a string ignores escape sequences
        String domainAndUsername = domain + @"\" + username;
        DirectoryEntry entry = new DirectoryEntry(_path, domainAndUsername, pwd);

        try
        {
            //Query the AD server
            DirectorySearcher search = new DirectorySearcher(entry);
            search.Filter = "(SAMAccountName=" + username + ")";
            search.PropertiesToLoad.Add("cn");
            SearchResult result = search.FindOne();
            if (result == null)
            {
                return false;
            }
            // Update the new path to the user in the directory
            _path = result.Path;
            _filterAttribute = (String)result.Properties["cn"][0];
        }
        catch (Exception ex)
        {
            throw new AuthenticationException(ex.Message);
        }
        return true;
    }

    public String GetGroups()
    {
        DirectorySearcher search = new DirectorySearcher(_path);
        search.Filter = "(cn=" + _filterAttribute + ")";
        search.PropertiesToLoad.Add("memberOf");
        StringBuilder groupNames = new StringBuilder();
        try
        {
            SearchResult result = search.FindOne();
            int propertyCount = result.Properties["memberOf"].Count;
            String dn;
            int equalsIndex, commaIndex;

            for (int propertyCounter = 0; propertyCounter < propertyCount; propertyCounter++)
            {
                dn = (String)result.Properties["memberOf"][propertyCounter];

                equalsIndex = dn.IndexOf("=", 1);
                commaIndex = dn.IndexOf(",", 1);
                if (-1 == equalsIndex)
                {
                    return null;
                }
                groupNames.Append(dn.Substring((equalsIndex + 1), (commaIndex - equalsIndex) - 1));
                groupNames.Append("|");
            }
        }
        catch (Exception ex)
        {
            throw new Exception("Error obtaining group names. " + ex.Message);
        }
        return groupNames.ToString();
    }
}